//
//  ViewController.m
//  CoreBluetooth_BLE_protocol
//
//  Created by wujia121 on 17/8/27.
//  Copyright © 2017年 steven. All rights reserved.
//

#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>

@interface ViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate> //需遵守2个协议

@property (strong, nonatomic) CBCentralManager *centerManager;
@property (nonatomic, strong) CBPeripheral *peripher;

@property (strong, nonatomic) CBCharacteristic *characteristic;

@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建蓝牙外设管理者，会回调centralManagerDidUpdateState
    self.centerManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
    
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
  
}

static NSString * const UUID_Character = @"CDD1";
static NSString * const UUID_Server = @"CDD2";


#pragma mark ============ CBCentralManagerDelegate ==============

// 创建中心设备管理器，会回调centralManagerDidUpdateState
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    if (central.state == CBManagerStatePoweredOn) {
        NSLog(@"蓝牙可用");
        // 根据SERVICE_UUID来扫描外设，如果不设置SERVICE_UUID，则扫描所有蓝牙设备
        //[central scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:UUID_Server]] options:nil];
        [central scanForPeripheralsWithServices:nil options:nil];
    }
    if(central.state == CBManagerStateUnsupported) {
        NSLog(@"该设备不支持蓝牙");
    }
    if (central.state == CBManagerStatePoweredOff) {
        NSLog(@"蓝牙已关闭");
    }
}

//当扫描到外设之后，就会回调下面这个方法，可以在这个方法中继续设置筛选条件，例如根据外设名字的前缀来选择，如果符合条件就进行连接。
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
    self.peripher = peripheral;
    NSLog(@"peripher.name:%@ \n services: %@",peripheral.name, peripheral.services);

    if ([peripheral.name hasPrefix:@"sj"]) {
        [central connectPeripheral:peripheral options:nil];
    }

    //中心连接外设
    [central connectPeripheral:peripheral options:nil];
}

//当连接成功的时候，就会来到下面这个方法。为了省电，当连接上外设之后，就让中心设备停止扫描，并且别忘记设置连接上的外设的代理。在这个方法里根据UUID进行服务的查找。
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    //省电,停止扫描
    [central stopScan];
    //外设连接成功，给它设置代理
    peripheral.delegate = self;
    //寻找外设的服务
    //[peripheral discoverServices:@[[CBUUID UUIDWithString:UUID_Server]]];
    [peripheral discoverServices:nil];
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"连接失败");
}

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"断开连接，尝试重连。。。");
    [central connectPeripheral:peripheral options:nil];
}


#pragma mark ============ CBPeripheralDelegate ==============
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    // 遍历出外设中所有的服务
    for (CBService *service in peripheral.services) {
        NSLog(@"所有的服务：%@",service);
        // 根据UUID寻找服务中的特征
        [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:UUID_Character]] forService:service];
        //[peripheral discoverCharacteristics:nil forService:nil];
    }
    
    
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {

    // 遍历出所需要的特征
    for (CBCharacteristic *characteristic in service.characteristics) {
        NSLog(@"所有特征：%@", characteristic);
        // 从外设开发人员那里拿到不同特征的UUID，不同特征做不同事情，比如有读取数据的特征，也有写入数据的特征
    }
    
    // 这里只获取一个特征，写入数据的时候需要用到这个特征
    self.characteristic = service.characteristics.lastObject;
    
    // 直接读取这个特征数据，会调用didUpdateValueForCharacteristic
    [peripheral readValueForCharacteristic:self.characteristic];
    
    // 订阅特征
    [peripheral setNotifyValue:YES forCharacteristic:self.characteristic]; //对这个特征进行订阅，订阅成功之后，就可以监控外设中这个特征值得变化了
}


//当订阅的特征的状态发生改变的时候，下面的方法就派上用场了
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

    if (error) {
        NSLog(@"订阅失败");
        NSLog(@"%@",error);
    }
    if (characteristic.isNotifying) {
        NSLog(@"订阅成功");
    } else {
        NSLog(@"取消订阅");
    }
}

/*
12、外设可以发送数据给中心设备，中心设备也可以从外设读取数据，当发生这些事情的时候，就会回调这个方法。通过特种中的value属性拿到原始数据，然后根据需求解析数据。
*/
/** 接收到数据回调 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    // 拿到外设发送过来的数据
    NSData *data = characteristic.value;
    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"接受到外设发送过来的数据:%@",msg);

}

/*
13、中心设备可以向外设写入数据，也可以向外设发送请求或指令，当需要进行这些操作的时候该怎么办呢。

首先把要写入的数据转化为NSData格式，然后根据上面拿到的写入数据的特征，运用方法writeValue:(NSData )data forCharacteristic:(CBCharacteristic )characteristic type:(CBCharacteristicWriteType)type来进行数据的写入。

当写入数据的时候，系统也会回调这个方法peripheral:(CBPeripheral )peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic )characteristic error:(nullable NSError *)error 。
*/

/** 写入数据 */
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSString *msg = @"哈哈哈哈";
    // 用NSData类型来写入
    NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
    // 根据上面的特征self.characteristic来写入数据
    [self.peripher writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
}


/** 写入数据回调 */
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
    NSLog(@"写入成功");
}

/*
14、中心设备如何主动从外设读取数据呢。

用正在连接的外设对象来调用readValueForCharacteristic方法，并且把将要读取数据的特征作为参数，这样就可以主动拿一次数据了。

去到第12步的回调方法中，在特征的value属性中拿到这次的数据。
*/

/** 读取数据 */
- (IBAction)didClickGet:(id)sender {
    [self.peripher readValueForCharacteristic:self.characteristic];
}





@end
